package org.webby.alert;

import org.webby.security.SealedValueService;
import org.webby.security.SealedValue;
import org.webby.security.ParseException;
import org.webby.StringUtil;
import org.webby.CookieUtil;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.net.URLEncoder;
import java.net.URLDecoder;
import java.io.UnsupportedEncodingException;

public class AlertService {
  public static final String servletContextAttributeName = "alertService";
  
  private static final String defaultCookieName = "alert";
  private static final String defaultAttrName = "alert";

  private final String cookieName;
  private final String attrName;
  private final SealedValueService sealedValueService;

  public AlertService(SealedValueService sealedValueService) {
    cookieName = defaultCookieName;
    attrName = defaultAttrName;
    this.sealedValueService = sealedValueService;
  }

  public AlertService(String cookieName, String attrName, SealedValueService sealedValueService) {
    this.cookieName = cookieName;
    this.attrName = attrName;
    this.sealedValueService = sealedValueService;
  }

  public void addAlert(HttpServletResponse response, String message) {
    try {
      Cookie c = new Cookie(cookieName, URLEncoder.encode(sealedValueService.seal(StringUtil.stringToBytes(message)).toBase64String(), "UTF-8"));
      c.setPath("/");
      response.addCookie(c);
    } catch (UnsupportedEncodingException e) {
      throw new RuntimeException(e);
    }
  }

  /**
   * Returns a validated alert from the request and clears the cookie. If there is not an alert, or there
   * is an alert but the sealed value cannot be verified, null is returned.
   *
   * @param request
   * @param response
   * @return
   */
  public String getValidAlert(HttpServletRequest request, HttpServletResponse response) {
    String rv = null;

    Cookie alertCookie = CookieUtil.getCookie(request, cookieName);
    if (alertCookie != null) {
      try {
        try {
          SealedValue sv = SealedValue.parseBase64String(URLDecoder.decode(alertCookie.getValue(), "UTF-8"));
          if (sealedValueService.verify(sv)) {
            rv = StringUtil.bytesToString(sv.getValue());
          } else {
            // TODO: log
            System.err.println("Could not verify alert from request " + request);
          }

          CookieUtil.clearCookie(request, response, cookieName);
        } catch (UnsupportedEncodingException e) {
          throw new RuntimeException(e);
        }
      } catch (ParseException e) {
        // TODO: log
        System.err.println("Error parsing sealed value " + e);
      }
    }

    return rv;
  }

  public void processRequest(HttpServletRequest request, HttpServletResponse response) {
    request.setAttribute(attrName, getValidAlert(request, response));      
  }
}